package com.linkhub.oms.admin.modules.stock.service;

import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Lists;
import com.linkhub.oms.admin.common.enums.NeedCheckDuplicatedBiz;
import com.linkhub.oms.admin.common.exception.ExceptionFactory;
import com.linkhub.oms.admin.modules.pickuporder.service.PickUpOrderBizService;
import com.linkhub.oms.admin.modules.stock.domain.dto.*;
import com.linkhub.oms.admin.modules.stock.enums.BusinessType;
import com.linkhub.oms.admin.modules.stock.exception.PreemptionFailException;
import com.linkhub.oms.admin.modules.stock.service.impl.*;
import com.linkhub.oms.admin.modules.wms.domain.dto.DeliveryListConfirmDTO;
import com.linkhub.oms.admin.modules.wms.domain.dto.ProcessOrderNoticeDTO;
import com.linkhub.oms.admin.modules.wms.domain.dto.WarehouseArrantConfirmDTO;
import com.linkhub.oms.admin.modules.wms.domain.dto.*;
import com.linkhub.oms.common.util.json.QtFastjsonUtil;
import com.linkhub.oms.dao.mpservice.IDuplicatedRecordService;
import com.linkhub.oms.dao.mpservice.IPickUpGoodsOrderService;
import com.linkhub.oms.data.sync.api.wms.domain.dto.WmsEntryOrderBatchCreateDTO;
import com.linkhub.oms.entity.PickUpGoodsOrderEntity;
import com.linkhub.oms.entity.PreemptionStockFlowEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * @ClassName StockHandlerAdapter
 * @Description TODO
 * @Author XieYu
 * @Date 2024/7/2 21:10
 * @Version 1.0
 */
@Slf4j
@Service
public class StockHandler {
    @Resource
    private PhysicalStockServiceImpl physicalStockService;
    @Resource
    private PassageStockBizServiceImpl passageStockService;
    @Resource
    private OutStockBizServiceImpl outStockBizService;
    @Resource
    private BatchBizServiceImpl batchBizService;
    @Resource
    private IDuplicatedRecordService duplicatedService;
    @Resource
    private PreemptionStockBizServiceImpl preemptionStockBizService;
    @Resource
    private IPickUpGoodsOrderService pickUpGoodsOrderService;
    @Resource
    private StockMaintainBizServiceImpl stockMaintainBizService;
    @Resource
    private PickUpOrderBizService pickUpOrderBizService;

    /**
     * @Author XieYu
     * @Description 入库单创建
     * @Date 2024/7/3 22:32
     * @Param [wmsEntryOrderBatchCreateDTO]
     * @return void
     */
    @Transactional(rollbackFor = Exception.class)
    public void wmsInboundCreated(WmsEntryOrderBatchCreateDTO wmsEntryOrderBatchCreateDTO) {
        log.info("库存管理-入库单创建-开始：{}", QtFastjsonUtil.toJSONString(wmsEntryOrderBatchCreateDTO));
        List<CreateInboundDTO> createInbounds = CreateInboundDTO.convert(wmsEntryOrderBatchCreateDTO);
        if (CollUtil.isNotEmpty(createInbounds)) {
            for (CreateInboundDTO createInbound : createInbounds) {
                passageStockService.wmsInboundCreated(createInbound);
            }
        }
        log.info("库存管理-入库单创建-结束");
    }

    /**
     * @Author XieYu
     * @Description 仓库入库单确认
     * @Date 2024/7/2 21:12
     * @Param [warehouseArrantConfirmDTO]
     * @return void
     */
    @Transactional(rollbackFor = Exception.class)
    public List<ConfirmInboundDTO> wmsInboundConfirm(WarehouseArrantConfirmDTO warehouseArrantConfirmDTO) {
        log.info("库存管理-入库单确认-开始：{}", QtFastjsonUtil.toJSONString(warehouseArrantConfirmDTO));

        BusinessType businessType = BusinessType.PURCHASE_RECEIPT;
        if ("WLTH".equals(warehouseArrantConfirmDTO.getEntryOrderType())) {
            log.info("接受的是物流退货入库单确认");
            businessType = BusinessType.RETURN_GOOD;
        }
        List<ConfirmInboundDTO> confirmInbounds = Collections.emptyList();
        if (businessType == BusinessType.RETURN_GOOD) {
            confirmInbounds = ConfirmInboundDTO.convert(warehouseArrantConfirmDTO, "0");
            if (CollUtil.isNotEmpty(confirmInbounds)) {
                for (ConfirmInboundDTO confirmInboundDTO : confirmInbounds) {
                    // 批次处理
                    long batchId = batchBizService.wmsInboundConfirm(confirmInboundDTO);
                    // 实物库存变化
                    physicalStockService.wmsInboundConfirm(businessType, batchId, confirmInboundDTO);
                    // 缺货变化
                    outStockBizService.minusStock(confirmInboundDTO.getUserId(), confirmInboundDTO.getSkuId(),
                            confirmInboundDTO.getStashName(), confirmInboundDTO.getSkuQuantity());
                }
            }
        } else {
            PickUpGoodsOrderEntity entryOrder = pickUpGoodsOrderService
                    .queryBySysEntryOrderCode(warehouseArrantConfirmDTO.getEntryOrderCode());
            if(entryOrder != null) {
                confirmInbounds = ConfirmInboundDTO.convert(warehouseArrantConfirmDTO, entryOrder.getSysSupplierId());
            }
            if (CollUtil.isNotEmpty(confirmInbounds)) {
                for (ConfirmInboundDTO confirmInboundDTO : confirmInbounds) {
                    // 在途流水变化
                    passageStockService.wmsInboundConfirm(confirmInboundDTO);
                    // 批次处理
                    long batchId = batchBizService.wmsInboundConfirm(confirmInboundDTO);
                    // 实物库存变化
                    physicalStockService.wmsInboundConfirm(businessType, batchId, confirmInboundDTO);
                    // 缺货变化
                    outStockBizService.minusStock(confirmInboundDTO.getUserId(), confirmInboundDTO.getSkuId(),
                            confirmInboundDTO.getStashName(), confirmInboundDTO.getSkuQuantity());
                }
                // 更新提货单状态
                boolean pickUpChangeSuccess = pickUpOrderBizService.wmsInbound(warehouseArrantConfirmDTO.getEntryOrderCode(), warehouseArrantConfirmDTO.isAllStockIn());
                if (!pickUpChangeSuccess) {
                    log.error("提货单状态变更失败，无法做入库确认");
                    throw ExceptionFactory.getI18nBizException("pickup.order.state.change.fail");
                }
            }
        }

        duplicatedService.finished(NeedCheckDuplicatedBiz.WMS_INBOUND_CONFIRM.name(),
                warehouseArrantConfirmDTO.getOutBizCode());

        log.info("库存管理-入库单确认-结束");
        return confirmInbounds;
    }

    /**
     * @Author XieYu
     * @Description 出库单确认
     * @Date 2024/7/7 13:36
     * @Param [deliveryListConfirmDTO]
     * @return void
     */
    @Transactional(rollbackFor = Exception.class)
    public void wmsOutboundConfirm(DeliveryListConfirmDTO deliveryListConfirmDTO) {
        log.info("库存管理-出库单确认-开始：{}", QtFastjsonUtil.toJSONString(deliveryListConfirmDTO));

        Pair<List<ConfirmOutboundDTO>, List<ConfirmOutboundDTO>> confirmOutboundDTOS = ConfirmOutboundDTO.convert(deliveryListConfirmDTO);
        if (CollUtil.isEmpty(confirmOutboundDTOS.getLeft()) && CollUtil.isEmpty(confirmOutboundDTOS.getRight())) {
            log.warn("库存管理-出库单确认-结束，无订单数据");
            return;
        }
        for (ConfirmOutboundDTO confirmOutboundDTO : confirmOutboundDTOS.getLeft()) {
            // 预占移除流水增加
            List<PreemptionStockFlowEntity> preemptionStockFlowEntities = preemptionStockBizService.wmsOutboundConfirm(confirmOutboundDTO);

            // 出库流水增加
            physicalStockService.wmsOutboundConfirm(confirmOutboundDTO, preemptionStockFlowEntities);
        }

        for (ConfirmOutboundDTO confirmOutboundDTO : confirmOutboundDTOS.getRight()) {  // 耗材处理
            physicalStockService.wmsOutboundConfirm(confirmOutboundDTO);
        }

        duplicatedService.finished(NeedCheckDuplicatedBiz.WMS_OUTBOUND_CONFIRM.name(),
                deliveryListConfirmDTO.getOutBizCode());
        log.info("库存管理-出库单确认-结束");
    }

    /**
     * @Author XieYu
     * @Description 订单预占
     * @Date 2024/7/6 16:58
     * @Param [orderProducts]
     * @return void
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean orderSubmitted(List<PreemptionDTO> preemptionList, boolean reSubmit) {
        log.info("库存管理-订单预占-开始：{}", QtFastjsonUtil.toJSONString(preemptionList));
        boolean flag = true;
        for (PreemptionDTO preemptionDTO : preemptionList) {
            int preemptionResult = preemptionStockBizService.preemption(BusinessType.SELL, preemptionDTO);
            if (!reSubmit && preemptionResult > 0) { // 不是重复预占，且缺口大于0
                outStockBizService.addStock(preemptionDTO.getUserId(), preemptionDTO.getSkuId(), preemptionDTO.getStashName(), preemptionResult);
                flag = false; // 有预占不足的情况就需要返回预占失败
            }
        }
        log.info("库存管理-订单预占-结束");
        return flag;
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean orderCancel(List<PreemptionDTO> preemptionList) {
        log.info("库存管理-订单预占取消-开始：{}", QtFastjsonUtil.toJSONString(preemptionList));

        for (PreemptionDTO preemptionDTO : preemptionList) {
            if (!preemptionStockBizService.orderCancel(preemptionDTO)) {
                log.info("库存管理-订单预占取消-失败");
                throw new PreemptionFailException(); // 不允许部分取消，故抛异常回滚
            }
            outStockBizService.minusStock(preemptionDTO.getUserId(), preemptionDTO.getSkuId(),
                    preemptionDTO.getStashName(), preemptionDTO.getSkuQuantity());
        }
        log.info("库存管理-订单预占取消-结束");
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean combineProcessingCreated(List<PreemptionDTO> preemptionList) {
        log.info("库存管理-组合加工预占-开始：{}", QtFastjsonUtil.toJSONString(preemptionList));

        for (PreemptionDTO preemptionDTO : preemptionList) {
            if (preemptionStockBizService.preemption(BusinessType.COMBINE_PROCESS, preemptionDTO) > 0) {
                // 组合加工预占失败则全部释放
                log.info("库存管理-组合加工预占-失败");

                throw new PreemptionFailException();
            }
        }
        log.info("库存管理-组合加工预占-结束");
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean wmsCombineProcessingConfirm(ProcessOrderNoticeDTO processOrderNoticeDTO) {
        log.info("库存管理-组合加工确认-开始：{}", QtFastjsonUtil.toJSONString(processOrderNoticeDTO));

        ConfirmCombineProcessingDTO confirmCombineProcessingDTO = ConfirmCombineProcessingDTO.convert(processOrderNoticeDTO);
        // 预占
        List<PreemptionStockFlowEntity> preemptionStockFlowEntities = preemptionStockBizService
                .wmsCombineProcessingConfirm(confirmCombineProcessingDTO);

        // 出库
        physicalStockService.wmsCombineProcessingConfirm(confirmCombineProcessingDTO, preemptionStockFlowEntities);

        List<ConfirmInboundDTO> confirmInboundDTOS = ConfirmInboundDTO.convert(processOrderNoticeDTO);
        for (ConfirmInboundDTO confirmInboundDTO : confirmInboundDTOS) {
            // 批次处理
            long batchId = batchBizService.wmsInboundConfirm(confirmInboundDTO);
            // 实物库存变化
            physicalStockService.wmsInboundConfirm(BusinessType.COMBINE_PROCESS, batchId, confirmInboundDTO);
        }
        duplicatedService.finished(NeedCheckDuplicatedBiz.WMS_COMBINE_PROCESSING_CONFIRM.name(),
                processOrderNoticeDTO.getOutBizCode());
        log.info("库存管理-组合加工确认-结束");
        return false;
    }

    /**
     * @Author XieYu
     * @Description 库存盘点
     * @Date 2024/7/13 22:26
     * @Param [stockCountNoticeDTO]
     * @return void
     */
    @Transactional(rollbackFor = Exception.class)
    public void wmsStockCheck(StockCountNoticeDTO stockCountNoticeDTO) {
        log.info("库存管理-库存盘点处理-开始：{}", QtFastjsonUtil.toJSONString(stockCountNoticeDTO));
        List<StockCheckDTO> stockCheckDTOS = StockCheckDTO.convert(stockCountNoticeDTO);
        // 实物库存增加
        for (StockCheckDTO stockCheckDTO : stockCheckDTOS) {
            stockMaintainBizService.wmsStockCheck(stockCheckDTO);
        }
        duplicatedService.finished(NeedCheckDuplicatedBiz.WMS_STOCK_CHECK.name(),
                stockCountNoticeDTO.getOutBizCode());
        log.info("库存管理-库存盘点处理-结束");
    }

    /**
     * @Author XieYu
     * @Description 库存转移
     * @Date 2024/7/13 22:26
     * @Param [transferOrderNoticeDTO]
     * @return void
     */
    @Transactional(rollbackFor = Exception.class)
    public void wmsStockTransfer(TransferOrderNoticeDTO transferOrderNoticeDTO) {
        log.info("库存管理-库存转移处理-开始：{}", QtFastjsonUtil.toJSONString(transferOrderNoticeDTO));

        List<StockTransferDTO> stockTransferDTOS = StockTransferDTO.convert(transferOrderNoticeDTO);
        for (StockTransferDTO stockTransferDTO : stockTransferDTOS) {
            stockMaintainBizService.wmsStockTransfer(stockTransferDTO);
        }

        duplicatedService.finished(NeedCheckDuplicatedBiz.WMS_STOCK_TRANSFER.name(), transferOrderNoticeDTO.getOutBizCode());

        log.info("库存管理-库存转移处理-结束");
    }

}
